package ch7.case7_1;

/**
 * 配置管理器
 * 系统管理模块在更新完系统的配置数据后通过该类将这种更新 “通知 ” 到ConfigurationHelper以及需要的业务模块对象
 */

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 该类可能导致死锁
 */
public enum ConfigurationManager {
    INSTANCE;

    // 这里用的是非线程安全的Set接口的HashSet实现类
    protected final Set<ConfigEventListener> listeners = new HashSet<ConfigEventListener>();

    // 加载配置信息
    public Configuration load(String name) {
        Configuration cfg = loadConfigurationFromDB(name);
        // 这里为什么要加上synchronized同步?
        // 是为了保障listeners这个变量同步， 防止在取到原来的配置数据后，listeners有更新
        synchronized (this) {
            for (ConfigEventListener listener : listeners) {
                listener.onConfigLoaded(cfg);
            }
        }
        return cfg;
    }

    // 从数据库加载配置实体（数据）
    private Configuration loadConfigurationFromDB(String name) {
        //...
        return null;
    }

    public synchronized void registerListener(ConfigEventListener listener) {
        listeners.add(listener);
    }

    public synchronized void removeListener(ConfigEventListener listener) {
        listeners.remove(listener);
    }

    /**
     * 该update方法在持有一个内部锁（ConfigurationManager当前实例对应的内部锁）的情况下，
     * 调用了一个外部方法， onConfigUpdated方法，而该方法内部又申请了另一个内部锁（ConfigurationHelper当前实例对应的内部锁）
     * @param name
     * @param newVersion
     * @param properties
     */
    public synchronized void update(String name, int newVersion, Map<String, String> properties) {
       for (ConfigEventListener listener : listeners) {
            // 该外部调用方法可能导致死锁
           listener.onConfigUpdated(name, newVersion, properties);
       }
    }
}
